using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace DAL
{
    public class Posts : DAL.DataManager<Post>
    {
        private static Posts Instance = new Posts();
        static Posts() { }

        public override string TableName
        {
            get { return @"yboard_posts"; }
        }

        public static string GetTableName()
        {
            return Instance.TableName;
        }

        protected override void CopyToItem(DataRow Row, Post Item)
        {
            if (Row["ThreadID"] != System.DBNull.Value)
            {
                Item.Thread = Threads.Item(Convert.ToInt64(Row["ThreadID"]));
            }
            else
            {
                Item.Thread = null;
            }

            Item.User = Users.Item(Convert.ToInt64(Row["UserID"]));


            if (Row["Subject"] != System.DBNull.Value)
            {
                Item.Subject = Convert.ToString(Row["Subject"]);
            }
            else
            {
                Item.Subject = null;
            }

            Item.Content = Convert.ToString(Row["Post"]);
            Item.DatePosted = Convert.ToDateTime(Row["DatePosted"]);

            if (Row["DateModified"] != System.DBNull.Value)
            {
                Item.DateModified = Convert.ToDateTime(Row["DateModified"]);
            }
            else
            {
                Item.DateModified = null;
            }

            Item.Visible = Convert.ToBoolean(Row["Visible"]);
        }

        protected override void CopyFromItem(DataManagerQuery query, Post Item)
        {
            if (Item.Thread != null)
            {
                query.AddParam("ThreadID", Item.Thread.ID);
            }
            else
            {
                query.AddParam("ThreadID", null);
            }


            query.AddParam("UserID", Item.User.ID);


            if (Item.Subject != null)
            {
                query.AddParam("Subject", Item.Subject);
            }
            else
            {
                query.AddParam("Subject", System.DBNull.Value);
            }


            query.AddParam("Post", Item.Content);
            query.AddParam("DatePosted", Item.DatePosted);

            if (Item.DateModified.HasValue)
            {
                query.AddParam("DateModified", Item.DateModified.Value);
            }
            else
            {
                query.AddParam("DateModified", null);
            }

            query.AddParam("Visible", Item.Visible);
        }

        public static Post Item(Int64 id)
        {
            return Instance.GetItem(id);
        }

        public static List<Post> All()
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("Visible", true);
            return Instance.GetItems(query);
        }

        public static void Add(Post Item)
        {
            if (Item.User.Status != User.UserStatus.Banned)
            {
                Item.Visible = true;
            }
            else
            {
                Item.Visible = false;
            }
            Item.DatePosted = DateTime.Now;
            Instance.Insert(Item);
            Item.User.TotalPosts += 1;
            Users.Save(Item.User);
            

            if (Item.Thread != null)
            {
                Item.Thread.TotalReplies = Posts.GetTotalPostsByThread(Item.Thread);
                Item.Thread.LastPost = Item;
                Threads.Save(Item.Thread);

                Item.Thread.Forum.TotalPosts += 1;
                Forums.Save(Item.Thread.Forum);
            }
        }

        public static void AddWithNewThread(Post Item, Forum destinationForum)
        {
            Add(Item);

            Thread myThread = new Thread();
            myThread.Forum = destinationForum;
            myThread.FirstPost = Item;
            myThread.LastPost = Item;
            Threads.Add(myThread);

            if (Item.User.Status == User.UserStatus.Banned)
            {
                myThread.Status = Thread.ThreadStatus.Deleted;
                Threads.Save(myThread);
            }

            Item.Thread = myThread;
            Save(Item);

            Item.User.TotalThreads += 1;
            Users.Save(Item.User);
        }

        private static void AddVisibleParam(DataManagerQuery query)
        {
            if (Managers.UserLoginManager.CurrentUser == null ||
                Managers.UserLoginManager.CurrentUser.Status != User.UserStatus.Banned)
            {
                query.AddParam("Visible", true);
            }
        }

        public static int GetTotalPostsByThread(Thread thread)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", thread.ID);
            AddVisibleParam(query);
            return Instance.GetCount(query) - 1;
        }

        public static void Save(Post Item)
        {
            Instance.Update(Item);
        }

        public static List<Post> GetByThread(Thread Thread)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", Thread.ID);
            AddVisibleParam(query);
            query.AddSort("ID", Sort.Asc);
            return Instance.GetItems(query);
        }

        public static DataManagerPage<Post> GetByThreadAndPage(Thread Thread, int page, int postsPerPage)
        {
            if (page < 0 || postsPerPage < 0)
            {
                page = 1;
                postsPerPage = 25;
            }
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", Thread.ID);
            AddVisibleParam(query);
            query.AddSort("ID", Sort.Asc);
            return Instance.GetItemsByPage(query, page, postsPerPage, true);
        }


        public static List<Post> GetLast25ByThread(Thread Thread)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", Thread.ID);
            AddVisibleParam(query);
            query.AddSort("ID", Sort.Desc);
            return Instance.GetItemsByPage(query, 1, 25).Items;
        }

        public static Post GetFirstPostByThread(Thread Thread)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", Thread.ID);
            AddVisibleParam(query);
            query.AddSort("ID", Sort.Asc);
            return Instance.GetItemsByPage(query, 1, 1).Items[0];
        }

        public static Post GetLastPostByThread(Thread Thread)
        {
            SqlCommand comm = new SqlCommand();
            comm.CommandText = "SELECT TOP 1 * FROM [" + Instance.TableName + "] WHERE ThreadID = @threadID AND Visible = 1 ORDER BY ID DESC";
            comm.Parameters.AddWithValue("@threadID", Thread.ID);
            return Instance.GetBySqlCommand(comm)[0];
        }


        public static int GetPageNumberFromPost(Post Item, int postsPerPage)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ThreadID", Item.Thread.ID);
            AddVisibleParam(query);
            query.AddParam("ID", Comparison.LessThanOrEqual, Item.ID);

            return (int)Math.Ceiling((float)Instance.GetCount(query) / (float)postsPerPage);

            // I don't like to do all this casting, but Math.Cieling has an overload for
            // for Math.Cieling(double) and Math.Cieling(decimal). It doesn't know which one
            // to call when diving two integers. Math.Cieling also returns a double, which needs
            // to be converted back to an int for the function.
        }

        public static int GetTotalPosts()
        {
            DataManagerQuery query = new DataManagerQuery();
            AddVisibleParam(query);
            return Instance.GetCount(query);
        }

        public static List<Post> Search(Helpers.ForumSearchHelper search, int page)
        {
            search.DisplayMode = Helpers.ForumSearchHelper.Display.AsPosts;
            SqlCommand comm = search.GenerateSearchSqlCommand(page);
            return Instance.GetBySqlCommand(comm);
        }
    }

    public class Post : DAL.DataManagerRow
    {
        private Thread _Thread;
        public Thread Thread
        {
            get
            {
                return _Thread;
            }
            set
            {
                _Thread = value;
            }
        }


        private User _User;
        public User User
        {
            get
            {
                return _User;
            }
            set
            {
                _User = value;
            }
        }


        private string _Subject;
        public string Subject
        {
            get
            {
                return _Subject;
            }
            set
            {
                _Subject = value;
            }
        }


        private string _Content;
        public string Content
        {
            get
            {
                return _Content;
            }
            set
            {
                _Content = value;
            }
        }

        private DateTime _datePosted;
        public DateTime DatePosted
        {
            get
            {
                return _datePosted;
            }
            set
            {
                _datePosted = value;
            }
        }

        private Nullable<DateTime> _dateModified;
        public Nullable<DateTime> DateModified
        {
            get
            {
                return _dateModified;
            }
            set
            {
                _dateModified = value;
            }
        }

        private bool _visible;
        public bool Visible
        {
            get
            {
                return _visible;
            }
            set
            {
                _visible = value;
            }
        }
    }
}